﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using FMODNet;
using System.Diagnostics;
using System.Threading;

using System.Configuration;

namespace FMODNET.Sample
{
    public partial class MainForm : Form
    {

        //static bool @lock = true;
        Random rnd = new Random();
        System.Windows.Forms.Timer th;
        int sndPos = 0;
        Sound _currentSound;
        private void SetTitle(Sound snd)
        {
            if (snd == null || snd.Channel == null)
                return;
            TimeSpan t1 = (TimeSpan.FromMilliseconds(snd.Channel.Position == -1 ? 0 : snd.Channel.Position));
            TimeSpan t2 = (TimeSpan.FromMilliseconds(snd.Length));
            string title = snd.Name;
            string tag = snd.GetAllTags().Where(c => c.ToLower().Contains("title")).FirstOrDefault();
            if (tag != null) title = snd.GetTagValue(tag);

            try
            {
                //if i update the title from another thread than the main thread, i have to make an async call to the main thread 
                //so it update the control from the proper context
                EventHandler hwnd = new EventHandler(delegate { this.Text = string.Format("{0}. {1} - {2}", title, t1, t2); });
                hwnd.SmartInvoke(this);
            }
            catch (ObjectDisposedException) { }
        }

        void updateSoundInfo()
        {
            Sound snd = _currentSound;
            Channel ch = snd != null ? snd.Channel : null;
            if (snd == null || ch == null) return;
            SetTitle(snd);

        }
        void selectListBox()
        {
            if (listBox1.SelectedIndex >= 0)
            {
                listBox1.SetSelected(listBox1.SelectedIndex, false);
            }
            listBox1.SetSelected(sndPos, true);
        }
        void PlayNextSound()
        {
            sndPos = (sndPos % listBox1.Items.Count);
            Sound snd = _currentSound;

            sndPos = chkRandom.Checked ? rnd.Next(listBox1.Items.Count) : sndPos++;
            
            EventHandler hwnd = (c, x) => { selectListBox(); };
            hwnd.SmartInvoke(listBox1);

            SoundInfo filename = listBox1.Items[sndPos] as SoundInfo;

            Sound sound = device.CreateSound(filename.Filename);
            _currentSound = sound;

            sound.Name = Path.GetFileNameWithoutExtension(filename.Filename);

            Fader fader = sound.AddDSP(new Fader(sound.Length - 6000, sound.Length, this.device));
            fader.Bypass = false;

            sound.Play();
            sound.AddCallback((uint)(10000), (c, x) => { });
            sound.AddCallback((uint)(sound.Length - 2000), (c, x) => PlayNextSound());
            sound.AddCallback((uint)(sound.Length - 6000), (c, x) => StartFeedFade(c));
            SetTitle(sound);
        }

        private void StartFeedFade(Sound c)
        {
            new Thread(() =>
                {
                    Sound mySound = c;
                    if (c == null)
                        return;

                    Fader dsp = mySound.GetDSP("Fader").FirstOrDefault() as Fader;
                    if (dsp == null)
                        return;

                    Channel myChannel = mySound.Channel;
                    if (myChannel == null)
                        return;
                    dsp.Bypass = false;

                    while (myChannel.IsPlaying)
                    {
                        //Dont bypass the dsp
                        int pos = 0;
                        try
                        {
                            pos = myChannel.Position;
                        }
                        catch (FMODException) { Trace.WriteLine("Could not read position"); }
                        if (pos > 0)
                        {
                            dsp.CurrentPosition = pos;
                        }
                        Thread.Sleep(1);
                    }
                }).Start();
        }

        class SoundInfo
        {
            public string Description { get; private set; }
            public int Length { get; private set; }
            public string Filename { get; private set; }
            public SoundInfo(string filename)
            {
                this.Filename = filename;
                this.Description = Path.GetFileNameWithoutExtension(filename);
            }
        }

        SoundDevice device = new SoundDevice();
        bool isToClose;
        public MainForm()
        {
            InitializeComponent();
            //brake_dll = device.LoadExternalPlugin("VCS-UltraChopper-Demo.dll");
            device.Initialize(new SoundDeviceConfiguration
                {
                    DebugMode = true,
                    MaximumAllowedSounds = 8,
                    StreamBufferSize = 65536
                });

            if (!loadAllMusics())
            {
                return;
            }
            //Start the update title thread
            th = new System.Windows.Forms.Timer()
            {
                Interval = 50,
                Enabled = true
            };
            th.Tick += delegate { updateSoundInfo(); };
            Thread.CurrentThread.Name = "Forms";
        }

        private bool loadAllMusics()
        {
            string listenDirectory = null;
            do
            {
                listenDirectory = ConfigurationManager.AppSettings["listenDirectory"];
                if (string.IsNullOrEmpty(listenDirectory))
                {
                    DialogResult res = MessageBox.Show("You have to configure the setting key 'listenDirectory' on your app.config\nPlease create the key and press ok to try again or cancel to abort", "Warning", MessageBoxButtons.OKCancel);
                    if (res != DialogResult.OK)
                    {
                        isToClose = true;
                        return false;
                    }
                    ConfigurationManager.RefreshSection("appSettings");
                }
            }
            while (string.IsNullOrEmpty(listenDirectory) || !Directory.Exists(listenDirectory));


            listBox1.DataSource = (from x in (Directory.GetFiles(listenDirectory, "*.mp3", SearchOption.AllDirectories)) select new SoundInfo(x)).ToList();
            listBox1.DisplayMember = "Description";
            listBox1.DoubleClick += changeMusic;
            return true;
        }
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (isToClose)
                this.Close();
        }

        void changeMusic(object sender, EventArgs e)
        {
            if (sender is ListBox)
            {
                sndPos = (sender as ListBox).SelectedIndex;
            }
            
            if (_currentSound != null)
            {
                _currentSound.Stop();
                _currentSound = null;
            }
            PlayNextSound();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
            if (_currentSound != null)
            {
                _currentSound.Stop();
                _currentSound = null;
            }
            device.Dispose();
            //thComercial.Abort();
        }
    }
    public static class Extensions
    {
        public static void SmartInvoke(this EventHandler hwnd, Control ctl)
        {
            if (ctl.InvokeRequired)
            {
                ctl.Invoke(hwnd);
            }
            else
            {
                hwnd(ctl, EventArgs.Empty);
            }
        }
    }
}